<?php
/**
 * @link      http://www.phpGrace.com
 * @copyright Copyright (c) 2010-2015 phpWit.
 * @license   http://www.phpGrace.com/license
 * @package   phpGrace
 * @author    haijun liu mail:5213606@qq.com
 * @version   1.1.1
 */

define('PG_START_MEMORY'    ,  memory_get_usage());
define('PG_START_TIME'      ,  microtime(true));
define('PG_INDEX_FILE_NAME' , 'index.php');
define('PG_VERSION'         ,  '1.1.1');
define('PG_DS'              ,  DIRECTORY_SEPARATOR);
define('PG_IN'              ,  dirname(__FILE__).PG_DS);

if(!defined('PG_FOLDER')){define("PG_FOLDER","Rice");}//自定义框架名称，

if(!defined('PG_POST_FILTER')){define('PG_POST_FILTER' , true);}
if(!defined('PG_DEBUG')) {define('PG_DEBUG'  , false);}
if(!defined('PG_ROUTE')){define('PG_ROUTE' , false);}
if(!defined('PG_CLOSE_CACHE')){define('PG_CLOSE_CACHE' , false);}


//framework directory
if(!defined('PG_PATH')){define('PG_PATH'  , './app');}
define('PG_CONTROLLER'  , 'controllers');
define('PG_MODEL'       , PG_IN.'models');
define('PG_CONF'        , 'config.php');
define('PG_TOOLS'       , 'tools');

require_once 'constant.php';//引入常用常量
// 页面后缀
if(!defined('PG_SUFFIX')){define('PG_SUFFIX' , false);}

//router 路由
function PG_Router(){
	if(isset($_GET['pathInfo'])){
		$path = $_GET['pathInfo'];
		unset($_GET['pathInfo']);
	}else{
		$path = 'index/index';
	}
	if(PG_SUFFIX){$path = str_replace(PG_SUFFIX, '', $path);}
	$router = explode('/', $path);
	if(empty($router[0])){array_shift($router);}
	if(PG_ROUTE){
		$routerArray = require(PG_PATH.'/router.php');
		if(array_key_exists($router[0], $routerArray)){
			$newRouter    = array(); 
			$newRouter[0] = $routerArray[$router[0]][0];
			$newRouter[1] = $routerArray[$router[0]][1];
			if(!empty($routerArray[$router[0]][2]) && is_array($routerArray[$router[0]][2])){
				$newRouter = array_merge($newRouter, $routerArray[$router[0]][2]);	
			}
			define("PG_PAGE",  1);
			return $newRouter;
		};
	}
	$router[0] = isset($router[0]) ?  $router[0] : 'index';
	$router[1] = isset($router[1]) ?  $router[1] : 'index';
	for($i = 2; $i < count($router); $i++){
		if(preg_match('/^page_(.*)('.PG_SUFFIX.')*$/Ui', $router[$i], $matches)){
			define("PG_PAGE",  intval($matches[1]));
			array_splice($router, $i, 1);
		}
	}
	if(!defined("PG_PAGE")){define("PG_PAGE",  1);}
	return $router;
}

//Exception 意外情况
class pgException extends Exception{
	public function __construct($message, $code = null, $previous = null){
		parent::__construct($message, $code, $previous);
	}
	public function showBug(){if(PG_DEBUG){include PG_IN.'templates'.PG_DS.'debug.php'; pgExit();}}
}

//common functions //常用函数小工具
function pgExit($msg = ''){exit($msg);}

function p($var, $type = false){
	if($type){var_dump($var);}else{print_r($var);}
}


//database object 加载数据库对象
function db($tableName, $configName = 'db'){
	$conf = sc($configName);
        $ddd=PG_FOLDER.'\tools\db';
	return $ddd::getInstance($conf, $tableName, $configName);
}

//model 加载模型
function model($modelName){
	$modelName = '\\'.PG_FOLDER.'\\models\\'.$modelName;
	$model = new $modelName();
	return $model;
}

//autoLoad 自动加载
function __pgAutoLoad($className){
	$fileUri = PG_IN.substr($className, strlen(PG_FOLDER)+1).'.php';
	if(PG_DS == '/'){$fileUri = str_replace('\\', '/', $fileUri);}
	if(is_file($fileUri)){require $fileUri;}
	
}
spl_autoload_register('__pgAutoLoad');

//工具实例化函数( 适用于不能使用命名空间的工具类 )
function tool($args){
	static $staticTools = array();
	$arguments = func_get_args();
	$className = array_shift($arguments);
	$className = '\\'.$className;
	if(empty($staticTools[$className])){
		$fileUri = PG_IN.PG_TOOLS.PG_DS.$className.'.php';
		if(!is_file($fileUri)){throw new pgException("类文件 {$className} 不存在");}
		include $fileUri;
		$staticTools[$className] = 1;
	}
	switch(count($arguments)){
		case 0 :
		return new $className();
		break;
		case 1 :
		return new $className($arguments[0]);
		break;
		case 2 :
		return new $className($arguments[0], $arguments[1]);
		break;
		case 3 :
		return new $className($arguments[0], $arguments[1], $arguments[2]);
		break;
		case 4 :
		return new $className($arguments[0], $arguments[1], $arguments[2], $arguments[3]);
		break;
		case 5 :
		return new $className($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4]);
		break;
	}
}

//base controller 子类基本控制器
class Spoon{
	public    $gets;
	public    $tableName  = null;
	public    $tableKey   = null;
	public    $db;
	public    $order      = null;
	public    $postFilter = true;
	public    $pageInfo   = array('', '', '');
	protected $cacher;
	protected $cachePre;
	protected $cacheName;
	
	public function __construct(){}
	
	public function __init(){
		if($this->tableName != null){$this->db = db($this->tableName);}
		//过滤POST
		if(!empty($_POST)){
			define('PG_POST', true);
			if(PG_POST_FILTER && $this->postFilter){
				$_POST = str_replace(array('<','>', '"', "'"),array('&lt;','&gt;', '&quot;', ''), $_POST);
			}
		}else{
			define('PG_POST', false);
		}
		//过滤GET
		if(!empty($_GET)){$_GET = str_replace(array('<','>', '"', "'"),array('&lt;','&gt;', '&quot;',''), $_GET);}
		if(!empty($this->gets)){$this->gets = str_replace(array('<','>', '"', "'"),array('&lt;','&gt;', '&quot;',''), $this->gets);}
	}
	
	public function index(){}
	
	
	
	protected function dataList($everyPagerNum = 20, $fields = '*'){
		if($this->order == null){$this->order = $this->tableKey.' desc';}
		$arr = $this->db->page($everyPagerNum)->order($this->order)->fetchAll($fields);
		$this->pager = $arr[1];
		return $arr[0];
	}
	
	protected function getDataById(){
		if(empty($this->gets[0])){return null;}
		return $this->db->where($this->tableKey .' = ?', array(intval($this->gets[0])))->fetch();
	}
	
	protected function getDefaultVal($exception = array()){
		if(empty($this->gets[0])){return null;}
		$data = $this->db->where($this->tableKey .' = ?', array(intval($this->gets[0])))->fetch();
		$jsonPreData = array();
		if(!empty($exception) && !is_array($exception)){$exception = explode(',', $exception);}
		foreach($data as $k => $v){
			if(!in_array($k, $exception)){
				$jsonPreData[$k] = $data[$k];
			}
		}
		echo '<script>$(function(){';
		echo 'var dataobject = '.json_encode($jsonPreData).';';
		if($data){
			foreach($data as $k => $v){if(!in_array($k, $exception)){echo '$("input[name='.$k.']").val(dataobject.'.$k.');';}}
		}
		echo '});</script>';
		return $data;
	}
	
	public function skipToIndex(){header('location:'.PG_SROOT); exit;}
	
	protected function getCacher(){
		if(!empty($this->cacher)){return null;}
		$config = sc('cache');
		if(empty($config)){throw new pgException('缓存设置错误');}
		if(!in_array($config['type'], sc('allowCacheType'))){throw new pgException('缓存类型错误');}
		$type = strtolower($config['type']);
		require PG_IN.'caches'.PG_DS.$type.'Cacher.php';
		$className = PG_FOLDER.'\\caches\\'.$type.'Cacher';
		$this->cacher   = $className::getInstance($config);
		$this->cachePre = $config['pre'];
	}
	
	protected function cache($name, $id = null, $queryMethod, $timer = 3600, $isSuper = true){
		if(PG_CLOSE_CACHE){
			$queryRes = $this->$queryMethod();
			$this->$name = $queryRes;
			return false;
		}
		$this->getCacher();
		$this->cacheName = $isSuper ? $this->cachePre.$name.$id : $this->cachePre.PG_C.PG_M.$name.$id;
		$this->cacheName = md5($this->cacheName);
		$cachedRes = $this->cacher->get($this->cacheName);
		if($cachedRes){$this->$name = $cachedRes; return true;}
		$queryRes = $this->$queryMethod();
		$this->cacher->set($this->cacheName, $queryRes, $timer);
		$this->$name = $queryRes;
	}
	
	public function clearCache(){
		$this->getCacher();
		$this->cacher->clearCache();
	}
	
	public function removeCache($name, $id = null, $isSuper = true){
		$this->getCacher();
		$name = $isSuper ? $this->cachePre.$name.$id : $this->cachePre.PG_C.PG_M.$name.$id;
		$name = md5($name);
		$this->cacher->removeCache($name);
	}
	
	protected function initVal($key, $val = ''){
		if(empty($this->gets[$key])){$this->gets[$key] = $val;}
	}
	
	protected function intVal($key, $val = 0){
		if(empty($this->gets[$key])){
			$this->gets[$key] = 0;
		}else{
			$this->gets[$key] = intval($this->gets[$key]);
		}
	}
}



//***************************************内置工具函数****************************************
 
 
 //正常PHP程序接收json型post转换
 function input($data) { 
    if($data=='array'){//将获取的json数据转换为数组！
        $message=json_decode(file_get_contents('php://input'), true);
    }else if($data=='json'){//将获取原始json信息！
       $message=file_get_contents('php://input');
    }else if($data=='telegram'){//将获取电报专用message数组下的数组！
		$message=json_decode(file_get_contents('php://input'), true);
		$message=$message['message'];
	}else{//将获取json文件型信息！
		$message=file_get_contents($data);
	}
   return $message;  
 }

//腾讯云函数接收post转换
function SCF ($evenet) {  
	$data = json_decode(json_encode($evenet), true);
    $data = json_decode($data['body'], true);
    $message = $data['message'];//索引信息类
return $message;  
}




//post提交工具
function post ($url, $data,$header='Content-Type: application/json;charset=utf-8',$ssl=FALSE) {  
	    $ch = curl_init();  
	    curl_setopt($ch, CURLOPT_URL, $url);
	    curl_setopt($ch, CURLOPT_POST, 1); 
	    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); //设置缓冲等待时间
	    curl_setopt($ch, CURLOPT_HTTPHEADER, array ($header));
	    curl_setopt($ch, CURLOPT_POSTFIELDS, $data); //传递一个作为HTTP “POST”操作的所有数据的字符串。 
	    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);  
	    // 线下环境不用开启curl证书验证, 未调通情况可尝试添加该代码
	   if(!$ssl) {
		    curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0); // 从证书中检查SSL加密算法是否存在
	        curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);// 对认证证书来源的检查
		}
	    $dataa = curl_exec($ch);
	    curl_close($ch);                
	    return $dataa;  
}



//get提交工具
function get($url){
   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, $url);
   curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
   curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
   $data = curl_exec($ch);
   curl_close($ch);
   return $data;
 }

//随机生成小数默认两位
function randFloat($count = 2,$min = 0, $max = 1) {
	$rand = $min + mt_rand() / mt_getrandmax() * ($max - $min);
	return floatval(number_format($rand,$count));  
	
}

//josn转换封装
 function json($data,$type = ''){
	 if($type=='json'){
	   return json_encode($data);
	 }else if($type=='array'){		  
       return json_decode($data,true);//转为数组
	 }else{
		exit (json_encode($data));
	 }	 
 } 	
  

//特殊字符过滤（针对TG字符冲突过滤）	
function Specialfilter($strParam){
    $regex = "/\/|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\+|\{|\}|\:|\<|\>|\?|\[|\]|\,|\.|\/|\;|\'|\`|\-|\=|\\\|\|/";
    return preg_replace($regex,"",$strParam);
}
 
    
//打印方法封装
 function e($data, $type = ''){
	 if($type=='v'){
	   var_dump(urldecode($data));
	 }else if($type=='p'){
       print_r(urldecode($data));
	 }else{
		echo(urldecode($data));
	 }
}


//步进调试方法封装
 function sbs($data, $type = ''){
	 if($type=='v'){
	   var_dump(urldecode($data));
	 }else if($type=='p'){
       print_r(urldecode($data));
	 }else{
		echo(urldecode($data));
	 }
}



//删除过滤表情符号
function removeEmojiChar($str){
    $mbLen = mb_strlen($str);
    $strArr = [];
    for ($i = 0; $i < $mbLen; $i++) {
        $mbSubstr = mb_substr($str, $i, 1, 'utf-8');
        if (strlen($mbSubstr) >= 4) {
            continue;
        }
        $strArr[] = $mbSubstr;
    }
    return implode('', $strArr);
}


//对象转数组
function objectToArray($obj) {
  $arr = is_object($obj) ? get_object_vars($obj) : $obj;
  if(is_array($arr)) {
    return array_map(__FUNCTION__, $arr);
  }else {
    return json_decode($arr,true);//将json转为数组
  }
}

//*******************************************************************************************


//自动创建分组
function Create_group($GROUPING){
	if(!is_dir($GROUPING)){
		include PG_IN.'Template.php'; 
		graceCreateApp($GROUPING);
		exit();
	}else{
		echo "警告：分组【".$GROUPING."】已被创建!<p>在请在入口文件处注释掉 Create_group() 函数";
		exit();
	}
}


/**
 * 修正POST参数
 * @param name 键名称
 * @param value 修正后的值
 * @return value
 */
function gracePOST($name, $value = ''){
	$_POST[$name] = empty($_POST[$name]) ? $value : $_POST[$name];
	return $_POST[$name];
}




//路径解析
function u($c, $m, $params = '', $page = null){
	$suffix = PG_SUFFIX ? PG_SUFFIX : '/';
	$page = $page != null ? '/page_'.$page : '';
	if(is_array($params)){
		return PG_SROOT.$c.'/'.$m.'/'.implode('/', $params).$page.$suffix;
	}else{
		if($params != ''){
			return PG_SROOT.$c.'/'.$m.'/'.$params.$page.$suffix;
		}else{
			return PG_SROOT.$c.'/'.$m.$page.$suffix;
		}
	}
}
//去除空白字符
function trimAll($str){
    $qian=array(" ","　","\t","\n","\r");
    $hou=array("","","","","");
    return str_replace($qian,$hou,$str); 
}

//option 选中状态
function isSelected($val1, $val2){
	if($val1 == $val2){echo ' selected="selected"';}
}

function dataToOption($data, $currentId = 0){
	foreach($data as $k => $v){
		if($currentId == $k){
			echo "<option value=\"{$k}\" selected=\"selected\">{$v}</option>".PHP_EOL;
		}else{
			echo "<option value=\"{$k}\">{$v}</option>".PHP_EOL;
		}
	}
}

/**
 * 当前分组内的自定义配置 [可按照格式进行自定义配置]
 * @param key1 配置名称1
 * @param key2 配置名称2
 * @return 对应配置值
 */
function c($key1, $key2 = null){
	static $config = null;
	if($config == null){$config = require PG_PATH.'/config.php';}
	if(is_null($key1)){return $config;}
	if(is_null($key2)){if(isset($config[$key1])){return $config[$key1];} return null;}
	if(isset($config[$key1][$key2])){return $config[$key1][$key2];}
	return null;
}

/**
 * 全局配置 [可按照格式进行自定义配置]
 * @param $key 配置名称1
 * @param $key 配置名称2
 */
function sc($key1 = null, $key2 = null){
	static $config = null;
	if($config == null){
		$config = require PG_IN.'config.php';
	}
	if(is_null($key1)){return $config;}
	if(is_null($key2)){if(isset($config[$key1])){return $config[$key1];} return null;}
	if(isset($config[$key1][$key2])){return $config[$key1][$key2];}
	return null;
}

/**
 * 时间、内存开销计算
 * @return array(耗时[毫秒], 消耗内存[K])
 */
function pgCost(){
	return array(
		round((microtime(true) - PG_START_TIME) * 1000, 2),
		round((memory_get_usage() - PG_START_MEMORY) / 1024, 2)
	);
}


// run log
function pgRunLog(){
	if(!PG_DEBUG){return false;}
	$cost = pgCost();
	echo '<script>console.log("'.PG_FOLDER.' Log '.date('Y-m-d H:i:s').':\n'.PG_C.'->'.PG_M.' - 运行时间:'. $cost[0] .'毫秒, 占用内存:' . $cost[1] .'k");</script>';
}

//基础模型
class graceModel{
	public $tableName    = null;
	public $tableKey     = null;
	public static $obj   = null;
	public static $mname = null;
	public $m            = null;
	public $error        = null;
	public function __construct(){
		if($this->tableName != null){$this->m = db($this->tableName);}
	}
	public function findById($id, $fields = '*'){
		return $this->m->where($this->tableKey.' = ?', array($id))->fetch($fields);
	}
	public function getSql(){return $this->m->getSql();}
	public function error(){
		return $this->m->error();
	}
}

// run 运行
try{
	$includedFiles = get_included_files();
	if(count($includedFiles) < 2){exit;}
	header('content-type:text/html; charset=utf-8');

	$router = PG_Router();
	$controllerName = $router[0];
	$mode = '/^([a-z]|[A-Z]|[0-9])+$/Uis';
	$res  = preg_match($mode, $controllerName);
	if(!$res){$controllerName = 'index';}
	$controllerFile = PG_PATH.'/'.PG_CONTROLLER.'/'.$controllerName.'.php';
	if(!is_file($controllerFile)){
		$controllerName = 'index';
		$controllerFile = PG_PATH.'/'.PG_CONTROLLER.'/index.php';
	}
	require $controllerFile;
	define('PG_C', $controllerName);
	//$controllerName = $controllerName.'Controller';//原始控制器类命名方法（保留）
	$controllerName = 'index_'.PG_FOLDER;//新改进控制器命名方法（在）用
	$controller = new $controllerName;
	if(!$controller instanceof Spoon){throw new pgException('[ '.$controllerName.' ] 必须继承自 grace');}
	$methodName = $router[1];
	$res  = preg_match($mode, $methodName);
	if(!$res){$methodName = 'index';}
	$graceMethods = array(
		'__init', 'display', 'json','dataList', 'getDataById', 'getDefaultVal', 
		'skipToIndex', 'getCacher', 'cache', 'clearCache', 'removeCache', 'initVal', 'intVal'
	);
	if(in_array($methodName, $graceMethods)){$methodName  = 'index';}
	if(!method_exists($controller, $methodName)){$methodName  = 'index';}
	define('PG_M', $methodName);
	define('PG_SROOT', str_replace(PG_INDEX_FILE_NAME, '', $_SERVER['PHP_SELF']));
	
	array_shift($router);
	array_shift($router);
	$controller->gets = $router;
	define('PG_URL', implode('/', $router));
	call_user_func(array($controller, '__init'));
	call_user_func(array($controller, $methodName));
	//if(PG_AUTO_DISPLAY){call_user_func(array($controller, 'display'));}
	pgRunLog();
}catch(pgException $e){$e->showBug();}